package com.cgs.query.client.helper;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cgs.query.configuration.ConfigProperties;
import com.cgs.query.exception.QueryException;
import com.cgs.query.service.IQueryService;
import org.apache.commons.beanutils.ConvertUtilsBean2;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * 客户端查询帮助器
 * 只能使用于一个project
 * 多个project时,需要自己声明多个
 * <p>
 * 参数解释
 * callName 调用名
 * param 参数map
 * queryTimeOut 查询超时
 * clazz 转化类型(使用fastJson)
 * pn 页码 1起
 * ps 页数
 */
public class QueryCenterHelper {

    private IQueryService queryService;
    private String projectName;
    private ConfigProperties configProperties;
    public static final ConvertUtilsBean2 cv = new ConvertUtilsBean2();


    public QueryCenterHelper(IQueryService queryService, String projectName, ConfigProperties configProperties) {
        this.queryService = queryService;
        this.projectName = projectName;
        this.configProperties = configProperties;
    }

    public List<Map<String, Object>> singleExecute(String callName) {
        return singleExecute(callName, new LinkedHashMap<>());
    }

    public List<Map<String, Object>> singleExecute(String callName, LinkedHashMap<String, Object> param) {
        return singleExecute(callName, param, configProperties.getQueryTimeout());
    }

    public List<Map<String, Object>> singleExecute(String callName, int queryTimeOut) {
        return singleExecute(callName, new LinkedHashMap<>(), queryTimeOut);
    }

    /**
     * 单条sql执行
     */
    public List<Map<String, Object>> singleExecute(String callName, LinkedHashMap<String, Object> param, int queryTimeOut) {
        if (queryTimeOut <= 0) {
            throw new QueryException("超时时间应该大于0");
        }
        return (List<Map<String, Object>>) queryService.execute(projectName, callName, param, queryTimeOut);
    }

    public <T> List<T> singleExecute(String callName, Class<T> clazz) {
        return singleExecute(callName, new LinkedHashMap<>(), clazz);
    }

    public <T> List<T> singleExecute(String callName, LinkedHashMap<String, Object> param, Class<T> clazz) {
        return singleExecute(callName, param, configProperties.getQueryTimeout(), clazz);
    }

    /**
     * 单条sql执行
     */
    public <T> List<T> singleExecute(String callName, LinkedHashMap<String, Object> param, int queryTimeOut, Class<T> clazz) {
        if (queryTimeOut <= 0) {
            throw new QueryException("超时时间应该大于0");
        }
        List<Map<String, Object>> result = singleExecute(callName, param, queryTimeOut);
        if (CollectionUtils.isEmpty(result)) {
            return Collections.emptyList();
        } else {
            return JSONArray.parseArray(JSONObject.toJSONString(result), clazz);
        }
    }

    public RunnerPagImpl<Map<String, Object>> paginateExecute(String callName, int pn, int ps) {
        return paginateExecute(callName, new LinkedHashMap<>(), configProperties.getQueryTimeout(), pn, ps);
    }

    public RunnerPagImpl<Map<String, Object>> paginateExecute(String callName, LinkedHashMap<String, Object> param, int pn, int ps) {
        return paginateExecute(callName, param, configProperties.getQueryTimeout(), pn, ps);
    }

    public RunnerPagImpl<Map<String, Object>> paginateExecute(String callName, LinkedHashMap<String, Object> param, int queryTimeOut, int pn, int ps) {
        param.put("pn", pn);
        param.put("ps", ps);
        List<Map<String, Object>> result = singleExecute(callName, param, queryTimeOut);
        if (result.size() == 1) {
            return new RunnerPagImpl<Map<String, Object>>((long) cv.convert(result.get(0).get("count"), Long.class), (List) result.get(0).get("content"));
        } else {
            return null;
        }
    }

    public <T> RunnerPagImpl<T> paginateExecute(String callName, int pn, int ps, Class<T> clazz) {
        return paginateExecute(callName, new LinkedHashMap<>(), configProperties.getQueryTimeout(), pn, ps, clazz);
    }

    public <T> RunnerPagImpl<T> paginateExecute(String callName, LinkedHashMap<String, Object> param, int pn, int ps, Class<T> clazz) {
        return paginateExecute(callName, param, configProperties.getQueryTimeout(), pn, ps, clazz);
    }

    /**
     * 分页执行
     */
    public <T> RunnerPagImpl<T> paginateExecute(String callName, LinkedHashMap<String, Object> param, int queryTimeOut, int pn, int ps, Class<T> clazz) {
        param.put("pn", pn);
        param.put("ps", ps);
        List<Map<String, Object>> result = singleExecute(callName, param, queryTimeOut);
        if (result.size() == 2) {
            return new RunnerPagImpl<>((long) cv.convert(result.get(0), Long.class), JSONArray.parseArray(JSONObject.toJSONString(result.get(1)), clazz));
        } else {
            return null;
        }
    }

    public Long countExecute(String callName) {
        return countExecute(callName, new LinkedHashMap<>(), configProperties.getQueryTimeout());
    }

    public Long countExecute(String callName, LinkedHashMap<String, Object> param) {
        return countExecute(callName, param, configProperties.getQueryTimeout());
    }

    public Long countExecute(String callName, int queryTimeOut) {
        return countExecute(callName, new LinkedHashMap<>(), queryTimeOut);
    }

    /**
     * 查询count
     */
    public Long countExecute(String callName, LinkedHashMap<String, Object> param, int queryTimeOut) {
        List<Map<String, Object>> result = singleExecute(callName, param, queryTimeOut);
        if (result.size() > 1) {
            Map<String, Object> row = result.get(0);
            if (row.size() >= 1) {
                Iterator<Object> iterator = row.values().iterator();
                if (iterator.hasNext()) {
                    return (long) cv.convert(row.values(), Long.class);
                }
            }
        }
        throw new QueryException("错误的返回类型");
    }

    /**
     * 脚本执行，会返回多个list<Map>
     */
    public List<List<Map<String, Object>>> scriptExecute(String callName, LinkedHashMap<String, Object> param, int queryTimeOut) {
        if (queryTimeOut <= 0) {
            throw new QueryException("超时时间应该大于0");
        }
        return (List<List<Map<String, Object>>>) queryService.execute(projectName, callName, param, queryTimeOut);
    }
}
